#pragma once
#include<vector>
#include<iostream>
#include <algorithm>
#include<assert.h>
#include<string>
using namespace std;

namespace zlog
{
    #define DEFAULT_BUFFER_SIZE 10*1024*1024
    #define BUFFER_THREADSOLE_SIZE 80*1024*1024
    #define INCREMENT_SIZE 1024*1024*10  

    class Buffer
    {
    public:
    Buffer():_buffer(DEFAULT_BUFFER_SIZE),_write_idx(0),_read_idx(0)
    {}
    //向缓冲区中写入数据
    void push(const char* data,size_t len)
    {
        //1.处理缓冲区中数据不足的情况(两种策略二选一)
        //1.1策略1：固定大小空间不够直接返回
        //   if(len > WriteAbleSize()) return;
        //1.2策略2：无限扩容
        EnsureSpaceEnough(len);
        //2.将数据拷贝到缓冲区中
        std::copy(data,data+len,&_buffer[_write_idx]);
        //3.移动写指针
        moveWriter(len);
    }
    //获取可读数据的起始地址
    const char* ReadPos()
    {
        return &_buffer[_read_idx];
    } 

    //获取可读数据长度和可写数据长度
    size_t ReadAbleSize()
    {  //双缓冲区不考虑空间循环使用,处理完就交换缓冲区
        return _write_idx - _read_idx;
    }
    size_t WriteAbleSize()
    {
        //对于扩容策略,不存在可写空间大小,因为总是可写
        //这个接口仅仅针对固定大小缓冲区提供
        return _buffer.size() - _write_idx;
    }

    //对读写指针的向后偏移操作
    void moveReader(size_t len)
    {
        assert(_read_idx + len <= _write_idx);
        _read_idx += len;  
    }
    void moveWriter(size_t len)
    {
            assert(_write_idx + len <= _buffer.size());
            _write_idx += len;
    }

    //判断缓冲区中是否为空(即判断读写指针是否相同)
    bool empty()
    {
        return _write_idx == _read_idx;
    }
    //初始化缓冲区的操作
    void Reset()
    {
        _write_idx = 0 ;//缓冲区中所有空间都是空闲的
        _read_idx = 0; //与_read_idex相等表示没有数据可读
    }
    //交换缓冲区
    void swap(Buffer& buf)
    {
        _buffer.swap(buf._buffer);
        std::swap(_write_idx,buf._write_idx);
        std::swap(_read_idx,buf._read_idx);
    }

    private:
    void EnsureSpaceEnough(size_t len)
    {
        //1.判断是否真的需要扩容
        if(len <= WriteAbleSize()) return;
        //2.超过阈值之前翻倍增长，超过后采用线性增长
        size_t newsize = 0;
        if(_buffer.size() <= BUFFER_THREADSOLE_SIZE) 
            newsize = _buffer.size() * 2 + len; //为了防止翻倍后空间还是不够加上len
        else
        newsize  = _buffer.size() + INCREMENT_SIZE + len;
        //3.扩容新空间
        _buffer.resize(newsize); 
    }
        
    private:
        vector<char> _buffer;
        size_t _read_idx;  //读指针
        size_t _write_idx; //写指针
    };
}